﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using QbservableHubTests.Client;
using Newtonsoft.Json.Linq;
using System.Diagnostics;
using QbservableCore.Serialization;
using System.Reactive.Linq;
using Moq;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Linq.Expressions;
using System.Xml;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using QbservableCore.Client;
using QbservableHubTests.Serialization;
using System.Collections.Generic;
using System.Reactive.Subjects;

namespace QbservableHubTests
{
    public static class AA
    {
        public static T To<T>(this IQbservable o)
        { // Name it as you like: As, Cast, To, ...
            return (T)o;
        }
    }

    [TestClass]
    public class SerializationTests
    {
        #region SmokeTrace_Test

        [TestMethod]
        public void SmokeTrace_Test()
        {
            var qb = new QbservableTestProxy<int>("F1");

            var xs = from item in qb
                     //select new { A = item, B = 6 };
                     where item % 2 == 0
                     //let val = item // Todo, make it work
                     select new { Item = item.ToString() };
                     //select new { Item = item.ToString(), Date = DateTime.Now.AddDays(item) }; // Todo, make it work
                     
            var serializer = CreateExpressionSerializer();
            var json = serializer.ToJson(xs.Expression);
            Trace.WriteLine(json);
            serializer = CreateExpressionSerializer();
            var obs = serializer.ToObservable(json);
            var data  = obs.ToEnumerable<object>();

            foreach (var item in data)
            {
                Trace.WriteLine(item.ToString());
            }
        }

        #endregion // SmokeTrace_Test

        #region ExpressionJsonExpression_Test

        [TestMethod]
        public void ExpressionJsonExpression_Test()
        {
            var mockTargetMappe = new Mock<IQbservableTargetResolver>();
            mockTargetMappe.Setup(m => m.ToQbservable(It.IsAny<string>()))
                .Returns(() => Observable.Return(42).AsQbservable());

            var qbsProxy = new QbservableTestProxy<int>("F1");
            var xs = from item in qbsProxy
                     where item % 2 == 0
                     select item + 1;

            //JToken json = ExpressionToJson.Transform(xs.Expression, DefaultQbservableConvention.Instance);
            //Trace.WriteLine(json.ToString());

            //IQbservable qbsReal = JsonToExpression.Transform(
            //    json,
            //   DefaultQbservableConvention.Instance,
            //    mockTargetMappe.Object);

        }

        #endregion // ExpressionJsonExpression_Test

        // TODO: method invocation should throw exception
        
        [TestMethod]
        public void FuncExpression_ToQueryString_ShouldBe_ODataValid_Test()
        {
            //Observable.Return(1).AsObservable()
        }

        [TestMethod]
        public void FuncExpression_ToJson_ShouldBe_ODataValid_Test()
        {
        }

        [TestMethod]
        public void WhereExpression_ToQueryString_ShouldBe_ODataValid_Test()
        {
        }

        [TestMethod]
        public void WhereExpression_ToJson_ShouldBe_ODataValid_Test()
        {
        }

        [TestMethod]
        public void QbservableTranslation_Test()
        {
            var qbs = Observable.Merge(Observable.Return(1), Observable.Return(2)).AsQbservable();
            var exp = qbs.Expression;

            var obs = qbs.AsObservable().Publish().RefCount();
            obs.Subscribe(v => Trace.WriteLine(v));
        }

        [TestMethod]
        public void MergeToJson_Test()
        {
            var qb1 = new QbservableTestProxy<int>("F1");
            var qb2 = new QZ<int>("F2");

            var qbs = Qbservable.Merge(qb1.Where(i => i % 2 == 0), qb2);

            //JToken json = ExpressionToJson.Transform(qbs.Expression, DefaultQbservableConvention.Instance);
            //Trace.WriteLine(json.ToString());


        }

        [TestMethod]
        public void ZipToJson_Test()
        {
            var qb1 = new QbservableTestProxy<int>("F1");
            var qb2 = new QZ<int>("F2");
            var qb3 = new QZ<int>("FBnaya").Where(v => v % 3 == 0);
            var qbs = Qbservable.Zip(qb1.Where(i => i % 2 == 0), qb2, qb3, (a, b, c) => a + b + c);

            //JToken json = ExpressionToJson.Transform(qbs.Expression, DefaultQbservableConvention.Instance);
            //Trace.WriteLine(json.ToString());


        }

        private static ExpressionSerializer CreateExpressionSerializer()
        {
            var translationSettings = new ExpressionSerializer
            {
                ContractResolver = new CustomContractResolver(),
                Binder = new CustomSerializationBinder(),
            };
            translationSettings.AddConverters(new CustomJsonConverter());
            translationSettings.TargetResolver = new TestTargetResolver();
            return translationSettings;
        }
    }
}
